home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume91 / utilitys / ed3_1_1 / part05 / eded.c
C/C++ Source or Header  |  1991-11-07  |  27KB  |  1,217 lines

  1. /*
  2.     eded.c: main editor code for ed3
  3.  
  4.     Editor for 3D shapes in triangular/polygonal face format 9/4/91
  5. which evolved from:
  6.     Editor for 3D shapes in simple triangular face format, Ben Discoe 5/8/90
  7. which evolved out of:
  8.     Editor for 3D shapes, using stevel's 3d library, Ben Discoe 3/30/90
  9. adapted from:
  10.     Cube Demo Program - By Steve Ludtke  cre : 1/3/90
  11. note: this version of the editor no longer contains any of Stevel's code.
  12.  
  13. 10-22-91 chg YZ to ZY
  14. 10-18-91 added more command line options
  15. 10-16-91 fix duplicate to completely deselct original
  16. 10-13-91 dynamically allocate action/operation buffers
  17.          loads defaults at startup
  18. 10-02-91 add lower-level version of add_face etc. for undo purposes
  19. 09-09-91 add add_poly(), finish_poly()
  20. 09-06-91 add convert_point_sub()
  21.          adapted to use coord instead of short
  22. 09-04-91 major fix to del_selected_faces()
  23. 09-02-91 add deselect_point()
  24. 08-26-91 added start_to_kill_face, start_to_kill_poly
  25.          chg select_and_kill to kill_segment (moved to ed3.c)
  26. 08-25-91 add del_poly
  27. 08-24-91 broke find_nearest_on_screen into 2 functions
  28. */
  29.  
  30. #define ED3TITLE "ED3 3D editor V 1.1"
  31.  
  32. #define DEFINE_GLOBALS
  33. #include "sysnogr.h"
  34.  
  35.  
  36. void main(argc, argv)
  37. int argc;
  38. char *argv[];
  39. {
  40.   char file_flag = 0;
  41.   char *buf;
  42.   char filename[60];
  43.  
  44.   MAX_POINTS = 500;
  45.   MAX_FACES = 1000;
  46.   MAX_POLYS = 500;
  47.   MAX_SELECT = 1000;    /* 2000 bytes */
  48.   mode = M_ADDP;        /* editing mode */
  49.   dmode = DM_XY;
  50.  
  51.   point = NULL;
  52.   face = NULL;
  53.   poly = NULL;
  54.   select_p = NULL;
  55.   action = NULL;
  56.   operation = NULL;
  57.  
  58.   points = faces = polys = selected = 0;
  59.   vector0.x = point0.x = 0;    /* these are constant "convenience" values */
  60.   vector0.y = point0.y = 0;
  61.   vector0.z = point0.z = 0;
  62.  
  63.   /* Initialize flags */
  64.   flags.assume_poly = 0;
  65.   flags.copy_made = 0;
  66.   flags.crosshair = 0;
  67.   flags.debug = 0;
  68.   flags.display_dtool = 0;
  69.   flags.display_type = 0;
  70.   flags.drag_dtool = 0;
  71.   flags.in_edit_area = 0;
  72.   flags.moving_points = 0;
  73.   flags.show_coords = 1;
  74.   flags.points_only = 0;
  75.   flags.faces_only = 0;
  76.   flags.exclusive_del = 1;
  77.   flags.undo_active = 1;
  78.  
  79.   colors.newface = 1;
  80.  
  81.   dtool_end[0].x = dtool_end[0].y = dtool_end[0].z = -80;
  82.   dtool_end[1].x = dtool_end[1].y = dtool_end[1].z = 80;
  83.   reset_zoom();
  84.  
  85.   strcpy(filename, "data");
  86.  
  87.   while (argc)
  88.   {
  89.     buf = argv[argc];
  90.  
  91.     if (!strncmp(buf, "help", 4) || (*buf == '?'))
  92.     {
  93.       printf("Usage: ed3 [-w] [-m] [-p] [simple 3d file]\n");
  94.       printf("  -w to run on the workbench screen\n");
  95.       printf("  -m to run on a medium-res screen\n");
  96.       printf("  -p to use the workbench palette\n");
  97.       exit(0);
  98.     }
  99.     else if (*buf == '-')
  100.     {
  101.       if (*(buf+1) == 'w') flags.display_type |= DF_WORKBENCH;
  102.       if (*(buf+1) == 'm') flags.display_type |= DF_MED_RES;
  103.       if (*(buf+1) == 'p') flags.display_type |= DF_SYS_PALETTE;
  104.     }
  105.     else
  106.     {
  107.       strncpy(filename, argv[1], 30);
  108.       file_flag = 1;
  109.     }
  110.     argc--;
  111.   }
  112.  
  113.   if (load_defaults() == OKAY)
  114.   {
  115.     action_bufsize = act_buf;
  116.     operation_bufsize = op_buf;
  117.   }
  118.   else
  119.   {
  120.     act_buf = action_bufsize = ACTIONBUF;
  121.     op_buf = operation_bufsize = OPERATIONS;
  122.   }
  123.  
  124.   allocate_arrays();    /* allocates room for MAX_() of each object type */
  125.   init_undo();            /* sets up the undo buffer (call AFTER allocate) */
  126.   open_stuff(2, ED3TITLE);        /* 2 bitplanes = 4 colors is plenty */
  127.  
  128.   if (file_flag) load_data(filename);    /* whatever was on the command line */
  129.   refresh_all();
  130.   if (flags.show_coords) draw_coords(0);
  131.  
  132.   while (1)
  133.   {
  134.     wait_for_message();            /* multitask nicely */
  135.  
  136.     handle_messages();            /* We are largely event driven */
  137.   }
  138. }
  139.  
  140.  
  141. void del_selected()    /* otherwise known as Erase */
  142. {
  143.     int i1;
  144.     index del_f, del_q, del_p, max_verts;
  145.  
  146.     if (selected < 3)    /* always a safe operation */
  147.     {
  148.         /* remove all boxes! */
  149.         for (i1 = 0; i1 < selected; i1++) box_point(select_p[i1]);
  150.  
  151.         begin_operation();
  152.         del_selected_points(0);
  153.         end_operation();
  154.     }
  155.     else
  156.     {
  157.         /* count how many faces/polys would get deleted */
  158.         del_selected_faces(1, &del_f, &del_q, &max_verts);
  159.  
  160.         /* and assume the worst case, all points deleted */
  161.         del_p = selected;
  162.  
  163.         if (!enough_room(0, 0, 0, del_p, del_f, del_q, 0, max_verts))
  164.         {
  165.             /* this operation will overflow the undo buffer! */
  166.             if (!tell_user_overflow()) return;
  167.         }
  168.         /* now that we're commited to this operation, remove all boxes! */
  169.         for (i1 = 0; i1 < selected; i1++) box_point(select_p[i1]);
  170.         begin_operation();
  171.         del_selected_faces(0, &del_f, &del_q, &max_verts);
  172.         if (flags.exclusive_del)
  173.             del_selected_points(0);
  174.         else
  175.             del_selected_points(1);    /* we can assume the points are loose */
  176.         end_operation();
  177.     }
  178.  
  179.     /* restore all boxes */
  180.     for (i1 = 0; i1 < selected; i1++) box_point(select_p[i1]);
  181.  
  182. }
  183.  
  184.  
  185. void del_selected_points(assume_loose)
  186. int assume_loose;    /* if set, we can assume all points are unconnected */
  187. {
  188.     uindex i1, i2, p;
  189.  
  190.     for (i1 = 0; i1 < selected; i1++)
  191.     {
  192.         p = select_p[i1];
  193.         if (!assume_loose)
  194.         {
  195.             if (point_is_on_a_face(p) >= 0 ||            /* if not loose, */
  196.                 point_is_on_a_poly(p) >= 0) continue;    /* skip this point */
  197.         }
  198.         draw_point(p, colors.erase);
  199.  
  200.         /* watch out! the point we delete causes higher points to
  201.             be shifted, points that MIGHT be selected! */
  202.         for (i2 = i1+1; i2 < selected; i2++)
  203.             if (select_p[i2] == points-1)
  204.             {
  205.                 select_p[i2] = p;
  206.                 break;
  207.             }
  208.  
  209.         delete_point(p);    /* low-level delete */
  210.         select_p[i1] = select_p[selected-1];    /* remove from array */
  211.         selected--;
  212.         i1--;            /* start from this point; don't skip! */
  213.     }
  214. }
  215.  
  216.  
  217. void del_point(p, assume_loose, silent)
  218. index p;
  219. int assume_loose;        /* it set, we can assume this point is not connected */
  220. int silent;
  221. {
  222.     index i1;
  223.  
  224.     if (p < 0 || p >= points) return;        /* must be valid */
  225.  
  226.     /* might be selected */
  227.     for (i1 = 0; i1 < selected; i1++)
  228.         if (select_p[i1] == p)
  229.         {
  230.             box_point(select_p[i1]);    /* deselect visually */
  231.             select_p[i1] = select_p[selected-1];    /* remove from list */
  232.             selected--;
  233.         }
  234.  
  235.     if (!assume_loose)    /* might be used in a face or poly; check! */
  236.     {
  237.         if (point_is_on_a_face(p) >= 0) return;
  238.         if (point_is_on_a_poly(p) >= 0) return;
  239.     }
  240.     draw_point(p, colors.erase);
  241.     if (silent)
  242.         delete_point0(p);
  243.     else
  244.         delete_point(p);
  245. }
  246.  
  247.  
  248. void convert_to_xyz(pixx, pixy)        /* screen -> global coordinates */
  249. pixel pixx, pixy;
  250. {
  251.     long mox = (pixx - x_center) * SCALE;
  252.     long moy = (y_center - pixy) * SCALE;    /* sign flip: y increases upward */
  253.  
  254.     switch(dmode)
  255.     {
  256.         case DM_XY: gx = mox+offset.x; gy = moy+offset.y; break;
  257.         case DM_XZ: gx = mox+offset.x; gz = moy+offset.z; break;
  258.         case DM_ZY: gz = mox+offset.z; gy = moy+offset.y; break;
  259.     }
  260. }
  261.  
  262.  
  263. void convert_to_xy(x, y, z)        /* global xyz -> pixel px, py */
  264. coord x, y, z;
  265. {
  266.     switch(dmode)
  267.     {
  268.         case DM_XY: px =  ((x-offset.x)/SCALE);
  269.                     py = -((y-offset.y)/SCALE); break;
  270.         case DM_XZ: px =  ((x-offset.x)/SCALE);
  271.                     py = -((z-offset.z)/SCALE); break;
  272.         case DM_ZY: px =  ((z-offset.z)/SCALE);
  273.                     py = -((y-offset.y)/SCALE); break;
  274.     }
  275.     px += x_center;
  276.     py += y_center;
  277. }
  278.  
  279.  
  280. void convert_points()
  281. {
  282.     register uindex i;
  283.  
  284.     for (i = 0; i < points; ++i) convert_point(i);
  285. }
  286.  
  287.  
  288. void convert_point(p)
  289. register uindex p;
  290. {
  291.     convert_to_xy(point[p].x, point[p].y, point[p].z);
  292.     point[p].px = px;
  293.     point[p].py = py;
  294.     point[p].code &= 0xfff0;
  295.     point[p].code |= ((px<edit_minx)<<3 | (px>sxmax)<<2 | (py<edit_miny)<<1 | (py>symax));
  296. }
  297.  
  298.  
  299. void convert_point_sub(edp)
  300. register EdPoint *edp;
  301. {
  302.     convert_to_xy(edp->x, edp->y, edp->z);
  303.     edp->px = px;
  304.     edp->py = py;
  305.     edp->code &= 0xfff0;
  306.     edp->code |= ((px<edit_minx)<<3 | (px>sxmax)<<2 | (py<edit_miny)<<1 | (py>symax));
  307. }
  308.  
  309.  
  310. void allocate_arrays()
  311. {
  312.     point = (EdPoint *)sys_alloc(MAX_POINTS*sizeof(EdPoint));
  313.     if (!point) sys_exit("not enough memory for point data.");
  314.  
  315.     face = (Face *)sys_alloc(MAX_FACES*sizeof(Face));
  316.     if (!face) sys_exit("no memory for face data.");
  317.  
  318.     poly = (Polygon *)sys_alloc(MAX_POLYS*sizeof(Polygon));
  319.     if (!poly) sys_exit("no memory for polygon data.");
  320.  
  321.     select_p = (index *)sys_alloc(MAX_SELECT*sizeof(index));
  322.     if (!select_p) sys_exit("no memory for selected points.");
  323.  
  324.     action = (char *)sys_alloc(action_bufsize);
  325.     if (!action) sys_exit("no memory for undo buffer(1)");
  326.  
  327.     operation = (Operation *)sys_alloc(operation_bufsize*sizeof(Operation));
  328.     if (!operation) sys_exit("no memory for undo buffer(2)");
  329. }
  330.  
  331.  
  332. index more_faces(new_faces)
  333. uindex new_faces;
  334. {
  335.     Face *new_face = NULL;
  336.     uindex i;    /* loop var for copying */
  337.  
  338.     if (!(new_face = (Face *)sys_alloc(new_faces * sizeof(Face))))
  339.     {
  340.         printf("no memory for more face data.");
  341.         screen_say("not enough memory for more faces!");
  342.         return -1;
  343.     }
  344.  
  345.     for (i = 0; i < faces; i++) new_face[i] = face[i];
  346.     sys_free(face, MAX_FACES*sizeof(Face));
  347.     MAX_FACES = new_faces;
  348.     face = new_face;
  349.     return 0;        /* to show we were successful */
  350. }
  351.  
  352.  
  353. index more_polys(new_polys)
  354. uindex new_polys;
  355. {
  356.     Polygon *new_poly = NULL;
  357.     uindex i;    /* loop var for copying */
  358.  
  359.     if (!(new_poly = (Polygon *)sys_alloc(new_polys * sizeof(Polygon))))
  360.     {
  361.         screen_say("not enough memory for more polys!");
  362.         return -1;
  363.     }
  364.  
  365.     for (i = 0; i < polys; i++) new_poly[i] = poly[i];
  366.     sys_free(poly, MAX_POLYS*sizeof(Polygon));
  367.     MAX_POLYS = new_polys;
  368.     poly = new_poly;
  369.     return 0;        /* to show we were successful */
  370. }
  371.  
  372.  
  373. index more_points(new_poi)
  374. uindex new_poi;
  375. {
  376.     /* we declare new arrays the size we want, copy from the old ones,
  377.         then destroy the old ones */
  378.     EdPoint *new_point = NULL;
  379.     uindex i;    /* loop var for copying */
  380.  
  381.     new_point = (EdPoint *) sys_alloc(new_poi * sizeof(EdPoint));
  382.     if (!new_point)
  383.     {
  384.         screen_say("not enough memory for more points!");
  385.         return -1;
  386.     }
  387.     for (i = 0; i < points; i++) new_point[i] = point[i];
  388.  
  389.     /* now destroy the old array and point at the new memory */
  390.     sys_free(point, MAX_POINTS*sizeof(EdPoint));
  391.     MAX_POINTS = new_poi;
  392.     point = new_point;
  393.     return 0;    /* to show we were successful */
  394. }
  395.  
  396.  
  397. void free_arrays()
  398. {
  399.     if (operation) sys_free(operation, operation_bufsize*sizeof(Operation));
  400.     if (action) sys_free(action, action_bufsize);
  401.     if (point) sys_free(point, MAX_POINTS*sizeof(EdPoint));
  402.     if (face) sys_free(face, MAX_FACES*sizeof(Face));
  403.     if (poly) sys_free(poly, MAX_POLYS*sizeof(Polygon));
  404.     if (select_p) sys_free(select_p, MAX_SELECT*sizeof(index));
  405. }
  406.  
  407.  
  408. void new()
  409. {
  410.     uindex i;
  411.  
  412.     if (changes)    /* changes have been made since last save/clear */
  413.     {
  414.         if (!tell_user_changes()) return;
  415.     }
  416.     selected = faces = points = 0;
  417.     for (i = 0; i < polys; i++) kill_poly(i);
  418.     polys = 0;
  419.     mode = M_ADDP;
  420.     refresh_all();        /* clears the screen */
  421. }
  422.  
  423.  
  424. void start_face(p)
  425. uindex p;
  426. {
  427.     if (p >= points) return;    /* must be valid */
  428.  
  429.     tri_up_point(p);
  430.     first_point = last_point = face[faces].p[0] = p;
  431.     new_seg = 1;
  432.     mode = M_MORE;
  433.     flags.shape = M_FACE;
  434.     draw_bars();
  435. }
  436.  
  437.  
  438. void start_poly(p)
  439. uindex p;
  440. {
  441.     if (p >= points) return;    /* must be valid */
  442.  
  443.     tri_up_point(p);
  444.     first_point = last_point = temp_poly[0] = p;
  445.     new_seg = 1;
  446.     mode = M_MORE;
  447.     flags.shape = M_POLY;
  448.     draw_bars();
  449. }
  450.  
  451.  
  452. void start_to_kill_face(p)
  453. uindex p;
  454. {
  455.     index fa;
  456.  
  457.     if (p >= points) return;    /* must be valid */
  458.  
  459.     fa = point_is_on_a_face(p);
  460.     if (fa < 0) return;
  461.  
  462.     tri_down_point(p);
  463.     first_point = last_point = face[faces].p[0] = p;
  464.     new_seg = 1;
  465.     mode = M_KMORE;
  466.     flags.shape = M_FACE;
  467.     draw_bars();
  468. }
  469.  
  470.  
  471. void start_to_kill_poly(p)
  472. uindex p;
  473. {
  474.     index po;
  475.  
  476.     if (p >= points) return;    /* must be valid */
  477.  
  478.     po = point_is_on_a_poly(p);
  479.     if (po < 0) return;
  480.  
  481.     tri_down_point(p);
  482.     first_point = last_point = temp_poly[0] = p;
  483.     new_seg = 1;
  484.     mode = M_KMORE;
  485.     flags.shape = M_POLY;
  486.     draw_bars();
  487. }
  488.  
  489.  
  490. /* returns 0 on failure, number of selected points if successful */
  491.  
  492. index select_point(p)
  493. uindex p;
  494. {
  495.     if (p >= points) return ((index)0);    /* must be valid */
  496.  
  497.     /* return if too many points selected */
  498.     if (selected >= MAX_SELECT) return ((index)0);
  499.  
  500.     /* return if point already selected */
  501.     if (pselected(p)) return 0;
  502.  
  503.     select_p[selected++] = p;    /* otherwise add it to the list */
  504.     point[p].code |= PF_SELECTED;
  505.     box_point(p);                /* and select it visually */
  506.  
  507.     return (index)selected;
  508. }
  509.  
  510.  
  511. void deselect_point(p)
  512. uindex p;
  513. {
  514.     uindex i1;
  515.  
  516.     if (p >= points) return;    /* must be valid */
  517.     if (!pselected(p)) return;    /* return if point isn't selected */
  518.  
  519.     /* remove it from the list */
  520.     for (i1 = 0; i1 < selected; i1++)
  521.     {
  522.         if (p == select_p[i1])
  523.         {
  524.             select_p[i1] = select_p[selected-1];
  525.             selected--;
  526.             break;
  527.         }
  528.     }
  529.     point[p].code &= ~PF_SELECTED;    /* turn off selected flag */
  530.     box_point(p);                    /* and deselect it visually */
  531. }
  532.  
  533.  
  534. void duplicate(do_faces)
  535. char do_faces;
  536. {
  537.     int add_p = 0, add_f = 0, add_q = 0;
  538.     uindex fa, po, j, k, n, p, max_verts = 0;
  539.     index in[MAX_EDGES], all_in;
  540.     char text[80];
  541.  
  542.     /* only works with some points selected */
  543.     if (!selected) return;
  544.  
  545.     if (flags.copy_made)
  546.     {
  547.         screen_say("Please move the points before you duplicate them again.");
  548.         return;
  549.     }
  550.     if (flags.undo_active)
  551.     {
  552.         add_p = selected;
  553.         if (do_faces)
  554.         {
  555.             for (fa = 0; fa < faces; fa++)        /* scan all faces */
  556.             {
  557.                 all_in = 1;
  558.                 for (j = 0; j < 3; j++)        /* scan each vertice point */
  559.                 {
  560.                     p = face[fa].p[j];
  561.                     in[j] = -1;
  562.                     for (k = 0; k < selected; k++)
  563.                         if (p == select_p[k]) in[j] = k;
  564.                     if (in[j] < 0) all_in = 0;
  565.                 }
  566.                 if (all_in) add_f++;
  567.             }
  568.  
  569.             for (po = 0; po < polys; po++)        /* scan all polys */
  570.             {
  571.                 all_in = 1;
  572.                 n = poly[po].verts;            /* number of vertices */
  573.                 for (j = 0; j < n; j++)        /* scan each vertice point */
  574.                 {
  575.                     p = poly[po].p[j];
  576.                     in[j] = -1;
  577.                     for (k = 0; k < selected; k++)
  578.                         if (p == select_p[k]) in[j] = k;
  579.                     if (in[j] < 0) all_in = 0;
  580.                 }
  581.                 if (all_in)
  582.                 {
  583.                     add_q++;
  584.                     if (n > max_verts) max_verts = n;
  585.                 }
  586.             }
  587.         }
  588.         if (!enough_room(add_p, add_f, add_q, 0, 0, 0, 0, max_verts))
  589.         {
  590.             /* this operation will overflow the undo buffer! */
  591.             if (!tell_user_overflow()) return;
  592.         }
  593.     }
  594.     if (points+selected >= MAX_POINTS)
  595.     {
  596.         if (more_points(points+selected+100))
  597.         {
  598.             sprintf(text, "increased face space to %d", MAX_FACES);
  599.             screen_say(text);
  600.         }
  601.         else
  602.             return;                /* failure */
  603.     }
  604.     begin_operation();
  605.     duplicate0(do_faces);
  606.     end_operation();
  607. }
  608.  
  609.  
  610. void duplicate0(do_faces)
  611. char do_faces;
  612. {
  613.     uindex fa, po, j, k, n, p, old_points, old_faces, old_polys;
  614.     index in[MAX_EDGES], all_in;
  615.  
  616.     /*** First copy the selected points ***/
  617.  
  618.     old_points = points;
  619.     old_faces = faces;
  620.     old_polys = polys;
  621.     for (p = 0; p < selected; p++)
  622.         point[points++] = point[select_p[p]];
  623.     screen_say(" copy of points created");
  624.  
  625.     /*** Then the faces, if desired ***/
  626.  
  627.     if (!do_faces) goto just_points;
  628.  
  629.     if (faces >= MAX_FACES)
  630.     {
  631.         screen_say(" Not enough room to duplicate faces!");
  632.         return;
  633.     }
  634.     for (fa = 0; fa < old_faces; fa++)        /* scan all faces */
  635.     {
  636.         all_in = 1;
  637.         for (j = 0; j < 3; j++)        /* scan each vertice point */
  638.         {
  639.             p = face[fa].p[j];
  640.             in[j] = -1;
  641.             for (k = 0; k < selected; k++)
  642.                 if (p == select_p[k]) in[j] = k;
  643.             if (in[j] < 0) all_in = 0;
  644.         }
  645.         if (all_in)
  646.         {
  647.             /* make a copy of the face */
  648.             add_face(old_points+in[0],
  649.                      old_points+in[1],
  650.                      old_points+in[2], face[fa].color, 0);    /* not silent */
  651.         }
  652.     }
  653.     /*** Now do the same thing for the polygons... ***/
  654.     for (po = 0; po < old_polys; po++)        /* scan all polys */
  655.     {
  656.         all_in = 1;
  657.         n = poly[po].verts;            /* number of vertices */
  658.         for (j = 0; j < n; j++)        /* scan each vertice point */
  659.         {
  660.             p = poly[po].p[j];
  661.             in[j] = -1;
  662.             for (k = 0; k < selected; k++)
  663.                 if (p == select_p[k]) in[j] = k;
  664.             if (in[j] < 0) all_in = 0;
  665.         }
  666.         if (all_in)        /* only copy if all vertices were selected */
  667.         {
  668.             allocate_poly(n, colors.newface);
  669.             for (j = 0; j < n; j++)
  670.                 poly[polys].p[j] = old_points+in[j];
  671.             finish_poly(0);
  672.         }
  673.     }
  674. just_points:
  675.     /* deselect te old points and */
  676.     /* select the COPY we've made of the points */
  677.     for (p = 0; p < selected; p++)
  678.     {
  679.         po = select_p[p];
  680.         point[po].code &= ~PF_SELECTED;    /* turn off selected flag */
  681. #if 0
  682.         box_point(po);                    /* and deselect it visually */
  683. #endif
  684.         select_p[p] = old_points++;
  685.     }
  686.     flags.copy_made = 1;
  687. }
  688.     
  689.     
  690. index add_point(x, y, z)    /* adds a point at given location */
  691. coord x, y, z;
  692. {
  693.     action_add_p(x, y, z);
  694.  
  695.     return add_point0(x, y, z);
  696. }
  697.  
  698.  
  699. index add_point0(x, y, z)    /* adds a point at given location */
  700. coord x, y, z;
  701. {
  702.     char text[80];
  703.  
  704.     if (points == MAX_POINTS-1)    /* if we're already at maximum points */
  705.     {
  706.         /* then try to increase the space available */
  707.         if (more_points(MAX_POINTS+100))
  708.             return (index)-1;    /* failure */
  709.         else
  710.         {
  711.             sprintf(text, "increased point space to %d", MAX_POINTS);
  712.             screen_say(text);
  713.         }
  714.     }
  715.  
  716.     point[points].x = x;
  717.     point[points].y = y;
  718.     point[points].z = z;
  719.     point[points].code = 0;
  720.     convert_point(points);
  721.     points++;
  722.  
  723.     return (index)(points-1);    /* return number of point just created */
  724. }
  725.  
  726.  
  727. void insert_point(where, x, y, z)    /* inserts a point into the point list */
  728. index where;
  729. coord x, y, z;
  730. {
  731.     uindex i1, vert;
  732.  
  733.     /* shuffle the point there to the end of the list */
  734.     for (i1 = 0; i1 < faces; i1++)
  735.         for (vert = 0; vert < 3; vert++)
  736.             if (face[i1].p[vert] == where) face[i1].p[vert] = points;
  737.  
  738.     for (i1 = 0; i1 < polys; i1++)
  739.         for (vert = 0; vert < poly[i1].verts; vert++)
  740.             if (poly[i1].p[vert] == where) poly[i1].p[vert] = points;
  741.     point[points] = point[where];
  742.  
  743.     /* now fill in the point at the insertion point */
  744.     point[where].x = x;
  745.     point[where].y = y;
  746.     point[where].z = z;
  747.     convert_point(where);
  748.     convert_point(points);
  749.  
  750.     /* it assumed that there is room for one more point */
  751.     points++;
  752. }
  753.  
  754.  
  755. /* a higher level add_face */
  756.  
  757. void add_face1(p0, p1, p2)
  758. {
  759.     add_face(p0, p1, p2, colors.newface, 0);
  760. }
  761.  
  762.  
  763. void add_face(p0, p1, p2, fcol, silent)
  764. uindex p0, p1, p2;
  765. short fcol;
  766. int silent;
  767. {
  768.     char text[80];
  769.  
  770.     if (p0 >= MAX_POINTS || p1 >= MAX_POINTS || p2 >= MAX_POINTS) return;
  771.  
  772.     if (faces == MAX_FACES-1)    /* if we're already at maximum faces */
  773.     {
  774.         /* then try to increase the space available */
  775.         if (more_faces(MAX_FACES+100))
  776.             return;                /* failure */
  777.         else
  778.         {
  779.             sprintf(text, "increased face space to %d", MAX_FACES);
  780.             screen_say(text);
  781.         }
  782.     }
  783.     if (!silent) action_add_f(p0, p1, p2, fcol);
  784.  
  785.     add_face0(p0, p1, p2, fcol);
  786. }
  787.  
  788.  
  789. void add_face0(p0, p1, p2, fcol)
  790. uindex p0, p1, p2;
  791. short fcol;
  792. {
  793.     face[faces].p[0] = p0;
  794.     face[faces].p[1] = p1;
  795.     face[faces].p[2] = p2;
  796.     face[faces].color = fcol;
  797.     faces++;
  798. }
  799.  
  800.  
  801. void insert_face(where, p0, p1, p2, fcol)
  802. index where;
  803. uindex p0, p1, p2;
  804. short fcol;
  805. {
  806.     face[faces] = face[where];    /* copy to the end */
  807.     face[where].p[0] = p0;
  808.     face[where].p[1] = p1;
  809.     face[where].p[2] = p2;
  810.     face[where].color = fcol;
  811.     faces++;
  812. }
  813.  
  814.  
  815. /* This function requires you to have the new points already prepared
  816.     in an array.  If this is not the case, use allocate_poly()
  817. */
  818.  
  819. void add_poly(n, pcol, array, silent)
  820. index n;
  821. short pcol;
  822. index *array;
  823. int silent;
  824. {
  825.     register index j, *ppp;    /* polygon point array pointer */
  826.  
  827.     allocate_poly(n, pcol);
  828.     ppp = (poly + polys)->p;
  829.     for (j = 0; j < n; j++)
  830.         *ppp++ = *array++;
  831.     finish_poly(silent);
  832. }
  833.  
  834. /***
  835.     allocate_poly() doesn't actually add a new polygon: it simply allocates
  836.     room for a given number of points.  Use it like:
  837.  
  838.     allocate_poly(num_points, colors.newface);
  839.     (fill in values like poly[polys].p[i] = blah)
  840.     finish_poly(0);
  841. ***/
  842.  
  843. void allocate_poly(verts, pcol)
  844. uindex verts;
  845. short pcol;
  846. {
  847.     char text[80];
  848.  
  849.     if (polys == MAX_POLYS-1)    /* if we're already at maximum polys */
  850.     {
  851.         /* then try to increase the space available */
  852.         if (more_polys(MAX_POLYS+100))
  853.             return;                /* failure */
  854.         else
  855.         {
  856.             sprintf(text, "increased poly space to %d", MAX_POLYS);
  857.             screen_say(text);
  858.         }
  859.     }
  860.     poly[polys].verts = verts;
  861.     poly[polys].color = pcol;
  862.     poly[polys].p = (uindex *)sys_alloc(verts<<1);
  863. }
  864.  
  865.  
  866. void finish_poly(silent)
  867. int silent;
  868. {
  869.     if (!silent)
  870.         action_add_q(poly[polys].verts, poly[polys].p, poly[polys].color);
  871.     polys ++;
  872. }
  873.  
  874.  
  875. void insert_poly(where, verts, array, col)
  876. index where;
  877. index verts;
  878. index *array;
  879. short col;
  880. {
  881.     index i;
  882.  
  883.     poly[polys] = poly[where];    /* copy to the end */
  884.     polys++;
  885.  
  886.     poly[where].verts = verts;
  887.     poly[where].color = col;
  888.     poly[where].p = (uindex *)sys_alloc(verts<<1);
  889.  
  890.     for (i = 0; i < verts; i++)
  891.         poly[where].p[i] = array[i];
  892. }
  893.  
  894.  
  895. /* a lower-level function that kills a point, no questions asked */
  896.  
  897. void delete_point(p)
  898. index p;
  899. {
  900.     action_del_p(p, point[p].x, point[p].y, point[p].z);
  901.     delete_point0(p);
  902. }
  903.  
  904.  
  905. void delete_point0(p)    /* even lower-level */
  906. index p;
  907. {
  908.     uindex i1, vert;
  909.  
  910.     /* make sure we don't strand one of the ends of the distance tool */
  911.     if (dtool_end[0].attached && dtool_end[0].p == p)
  912.     {
  913.         dtool_end[0].x = point[p].x;
  914.         dtool_end[0].y = point[p].y;
  915.         dtool_end[0].z = point[p].z;
  916.         dtool_end[0].attached = 0;
  917.     }
  918.     if (dtool_end[1].attached && dtool_end[1].p == p)
  919.     {
  920.         dtool_end[1].x = point[p].x;
  921.         dtool_end[1].y = point[p].y;
  922.         dtool_end[1].z = point[p].z;
  923.         dtool_end[1].attached = 0;
  924.     }
  925.  
  926.     if (points == 1 || p == points-1)    /* only one, or last point */
  927.          { points--; return; }            /* simplest case */
  928.  
  929.     /* we shift the last point into the space occupied by the point we're
  930.         deleting, so make sure that faces still refer to the right points */
  931.     for (i1 = 0; i1 < faces; i1++)
  932.         for (vert = 0; vert < 3; vert++)
  933.             if (face[i1].p[vert] == points-1) face[i1].p[vert] = p;
  934.  
  935.     for (i1 = 0; i1 < polys; i1++)
  936.         for (vert = 0; vert < poly[i1].verts; vert++)
  937.             if (poly[i1].p[vert] == points-1) poly[i1].p[vert] = p;
  938.  
  939.     point[p] = point[points-1];    /* replace the p'th point with the last */
  940.     points --;                    /* and reduce number of points */
  941. }
  942.  
  943.  
  944. void delete_face(f, silent)
  945. register uindex f;
  946. int silent;
  947. {
  948.     if (!silent) action_del_f(f);
  949.  
  950.     if (f >= faces) return;            /* must be valid */
  951.  
  952.     if (faces != 1 && f != faces-1)    /* only one, or last face */
  953.         face[f] = face[faces-1];    /* replace the f'th face with the last */
  954.     faces --;                    /* and reduce number of faces */
  955. }
  956.  
  957.  
  958. void delete_poly(q, silent)
  959. register uindex q;
  960. int silent;
  961. {
  962.     if (!silent) action_del_q(q);
  963.  
  964.     if (q >= polys) return;        /* must be valid */
  965.  
  966.     kill_poly(q);                /* free its buffer */    
  967.  
  968.     if (polys != 1 && q != polys-1)    /* only one, or last face */
  969.         poly[q] = poly[polys-1];    /* replace the f'th face with the last */
  970.     polys --;                    /* and reduce number of faces */
  971. }
  972.  
  973.  
  974. void kill_poly(p)
  975. register uindex p;
  976. {
  977.     register uindex n = poly[p].verts;
  978.  
  979.     if (flags.debug) printf("killing poly %d: %d vertices.\n", p, n);
  980.     sys_free(poly[p].p, n<<1);
  981. }
  982.  
  983.  
  984. /* returns the number of faces, polys [potentially] deleted */
  985. /* also the greatest number of vertices on any poly */
  986.  
  987. void del_selected_faces(just_count, faces_del, polys_del, max_verts)
  988. int just_count;    /* If true, don't delete anything, just count how many
  989.                     *would* get deleted */
  990. index *faces_del;
  991. index *polys_del;
  992. index *max_verts;
  993. {
  994.     int fa, po;
  995.     register uindex i1, verts;
  996.  
  997.     *faces_del = 0;
  998.     *polys_del = 0;
  999.     *max_verts = 0;
  1000.  
  1001.     if (flags.exclusive_del)
  1002.     {
  1003.         short found;
  1004.  
  1005.         /* count down since we're deleting! */
  1006.         if (faces)
  1007.         for (fa = faces-1; fa >= 0; fa--)
  1008.         {
  1009.             if (pselected(face[fa].p[0]) &&
  1010.                 pselected(face[fa].p[1]) &&
  1011.                 pselected(face[fa].p[2]))
  1012.             {
  1013.                 if (!just_count) del_face(fa, 0);
  1014.                 (*faces_del) ++;
  1015.             }
  1016.         }
  1017.         if (polys)
  1018.         for (po = polys-1; po >= 0; po--)
  1019.         {
  1020.             found = 0;
  1021.             verts = poly[po].verts;
  1022.  
  1023.             for (i1 = 0; i1 < verts; i1++)
  1024.                 if (pselected(poly[po].p[i1])) found ++;
  1025.  
  1026.             if (found == verts)
  1027.             {
  1028.                 if (!just_count) del_poly(po, 0);
  1029.                 if (verts > *max_verts) *max_verts = verts;
  1030.                 (*polys_del) ++;
  1031.             }
  1032.         }
  1033.     }
  1034.     else
  1035.     {
  1036.         /* count down since we're deleting! */
  1037.         if (faces)
  1038.         for (fa = faces-1; fa >= 0; fa--)
  1039.         {
  1040.             if (pselected(face[fa].p[0]) ||
  1041.                 pselected(face[fa].p[1]) ||
  1042.                 pselected(face[fa].p[2]))
  1043.             {
  1044.                 if (!just_count) del_face(fa, 0);
  1045.                 (*faces_del) ++;
  1046.             }
  1047.         }
  1048.         if (polys)
  1049.         for (po = polys-1; po >= 0; po--)
  1050.         {
  1051.             verts = poly[po].verts;
  1052.  
  1053.             for (i1 = 0; i1 < verts; i1++)
  1054.             if (pselected(poly[po].p[i1]))
  1055.             {
  1056.                 if (!just_count) del_poly(po, 0);
  1057.                 if (verts > *max_verts) *max_verts = verts;
  1058.                 (*polys_del) ++;
  1059.                 break;
  1060.             }
  1061.         }
  1062.     }
  1063. }
  1064.  
  1065.  
  1066. void insert_vertex(q, vert, p0, silent)
  1067. index q, p0;
  1068. char vert;        /* insert at this position */
  1069. int silent;
  1070. {
  1071.     unsigned short *new, *old;
  1072.     unsigned short v1, v2, verts;    /* vertex counters */
  1073.  
  1074.     old = poly[q].p;
  1075.     verts = poly[q].verts;
  1076.  
  1077.     if (vert > verts) return;        /* safety: must be a valid point */
  1078.     new = (uindex *)sys_alloc((verts+1)<<1);
  1079.  
  1080.     for (v1 = 0, v2 = 0; v1 < verts; v1++)
  1081.     {
  1082.         if (v1 == vert) new[v2++] = p0;
  1083.         new[v2++] = old[v1];
  1084.     }
  1085.     if (v1 == vert) new[v2++] = p0;    /* perhaps we insert at the end */
  1086.     poly[q].p = new;
  1087.     sys_free(old, verts<<1);    /* free the old point array */
  1088.     poly[q].verts = verts + 1;
  1089. }
  1090.  
  1091.  
  1092. /* delete a specified vertex from a polygon */
  1093.  
  1094. void delete_vertex(q, vert, silent)
  1095. index q;
  1096. unsigned char vert;
  1097. int silent;
  1098. {
  1099.     unsigned short *new, *old;
  1100.     unsigned short v1, v2, verts;    /* vertex counters */
  1101.  
  1102.     old = poly[q].p;
  1103.     verts = poly[q].verts;
  1104.  
  1105.     if (vert >= verts) return;        /* safety: must be a valid point */
  1106.     if (!silent) action_del_v(q, vert, old[vert]);
  1107.     new = (uindex *)sys_alloc((verts-1)<<1);
  1108.  
  1109.     for (v1 = 0, v2 = 0; v1 < verts; v1++)
  1110.     {
  1111.         if (v1 == vert) continue;    /* skip the deleted point */
  1112.         new[v2++] = old[v1];
  1113.     }
  1114.     poly[q].p = new;
  1115.     sys_free(old, verts<<1);    /* free the old point array */
  1116.     poly[q].verts = verts - 1;
  1117. }
  1118.  
  1119.  
  1120. /* convert a face into a 3-point polygon */
  1121. #if 0
  1122. void face_to_poly(f, silent)
  1123. index f;
  1124. int silent;
  1125. {
  1126.     allocate_poly(3, face[f].color);
  1127.     poly[polys].p[0] = face[f].p[0];
  1128.     poly[polys].p[1] = face[f].p[1];
  1129.     poly[polys].p[2] = face[f].p[2];
  1130.     finish_poly(silent);
  1131. }
  1132. #endif
  1133.  
  1134. /* convert a 3-point polygon into a face */
  1135.  
  1136. void poly_to_face(q, silent)
  1137. index q;
  1138. int silent;
  1139. {
  1140.     uindex *p = poly[q].p;
  1141.  
  1142.     if (!silent) action_morph_q(q);
  1143.     add_face(p[0], p[1], p[2], poly[q].color, 1);
  1144. }
  1145.  
  1146.  
  1147. /*    Should we test distance from the global or on-screen cursor?
  1148.     if we use the on-screen cursor, there will be ambiguity of
  1149.     points behind each other.  If we use global 3D distances, the
  1150.     user will have to be VERY careful where the global cursor is.
  1151.  
  1152.     Both methods are implemented here.
  1153. */
  1154.  
  1155. /* returns the point nearest to {pixx, pixy} */
  1156.  
  1157. index find_nearest_on_screen(pixx, pixy, avoid_p)
  1158. pixel pixx, pixy;
  1159. index avoid_p;        /* avoid this point */
  1160. {
  1161.     index p;
  1162.     short found = -1;    /* -1 means failure */
  1163.     pixel dx, dy;
  1164.     long dist, nearest = 10000;
  1165.  
  1166.     /* if we don't have any points, nothing to select */
  1167.     if (!points) return (index)-1;
  1168.  
  1169.     for (p = 0; p < points; p++)
  1170.     {
  1171.         if (p == avoid_p) continue;
  1172.         convert_to_xy(point[p].x, point[p].y, point[p].z);
  1173.         dx = pixx - px;
  1174.         dy = pixy - py;
  1175.         dist = isqrt(dx*dx + dy*dy);
  1176.         if (dist < nearest) { nearest = dist; found = p; }
  1177.     }
  1178.     return found;
  1179. }
  1180.  
  1181.  
  1182. /* returns the point nearest to {fx, fy, fz} */
  1183.  
  1184. index find_nearest_in_space(fx, fy, fz, avoid_p)
  1185. coord fx, fy, fz;
  1186. index avoid_p;        /* do NOT consider this point */
  1187. {
  1188.     index p;
  1189.     short found = -1;    /* -1 means failure */
  1190.     coord dx, dy, dz;
  1191. #if INTEGER
  1192.     long dist, nearest = 10000;
  1193. #else
  1194.     double dist, nearest = 10000.0;
  1195. #endif
  1196.  
  1197.     /* if we don't have any points, nothing to select */
  1198.     if (!points) return (index)-1;
  1199.  
  1200.     for (p = 0; p < points; p++)
  1201.     {
  1202.         if (p == avoid_p) continue;
  1203.         dx = fx - point[p].x;
  1204.         dy = fy - point[p].y;
  1205.         dz = fz - point[p].z;
  1206. #if INTEGER
  1207.         dist = isqrt(dx*dx + dy*dy + dz*dz);
  1208. #else
  1209.         dist = sqrt(dx*dx + dy*dy + dz*dz);
  1210. #endif
  1211.         if (dist < nearest) { nearest = dist; found = p; }
  1212.     }
  1213.     return found;
  1214. }
  1215.  
  1216.  
  1217.